Skip to content

feat: Add comments to content engine - #904

Merged
aXenDeveloper merged 1 commit into
feat/content_engine_notificationsfrom
feat/comments_content_engine
Oct 27, 2026
Merged

aXenDeveloper merged 1 commit into
feat/content_engine_notificationsfrom
feat/comments_content_engine

Conversation

@aXenDeveloper

Copy link
Copy Markdown
Owner

Improving Documentation

Description

What?

Why?

@github-actions github-actions Bot added the 💡 Feature A new feature label Oct 26, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-27T13:20:08.137222Z 3244eed New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

github-actions Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

React Doctor found 7 new issues in 5 files · 1 error & 6 warnings · score 84 / 100 (Needs work) · 4 fixed · vs canary

Errors

6 warnings

src/pages/post-comments.tsx

  • ⚠️ L159 React function has high control-flow complexity no-high-complexity-react-function
  • ⚠️ L758 Heading has no content heading-has-content

src/tanstack/comments/content-comments.tsx

  • ⚠️ L163 React function has high control-flow complexity no-high-complexity-react-function
  • ⚠️ L571 Heading has no content heading-has-content

src/tanstack/comments/item.tsx

  • ⚠️ L166 React function has high control-flow complexity no-high-complexity-react-function

src/views/admin/views/core/users/roles/role-form-content.tsx

  • ⚠️ L249 React function has high control-flow complexity no-high-complexity-react-function

Reviewed by React Doctor for commit 3244eed. See inline comments for fixes.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b1e55ed2d0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +294 to +298
row: deleted,
});
};

if (await hasReplies(id)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Exclude deleted thread placeholders from search indexing

When a comment with replies is deleted, this update retains its body and published status in the database. Although the immediate syncContentSearch(..., { operation: "delete" }) removes its search document, search-indexer.ts does not select deletedAt, and isContentRowPublic in search-document.ts does not check it. A search rebuild—or reindexing dependent comments after an article edit—therefore publishes the deleted comment's text again in search, Discover and profile timelines. Carry the deletion state through indexing and prevent placeholders from becoming public documents.

Useful? React with 👍 / 👎.

Comment on lines +133 to +135
.select(selection)
.from(table)
.where(inArray(itemIdColumn, [...ids])),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Filter related translations by their publication state

For a published article with an unpublished or scheduled default-language translation, this query still loads that translation's title and slug, and the selection loop prefers it over published translations. loadRelatedContexts merges those values with the base article's published status without reading the translation's status or publication date, so contentSearchDocument exposes the draft title and URL through public comment search documents. Apply the translation publication predicate before choosing a related translation, as localized-public-service.ts does for public reads.

Useful? React with 👍 / 👎.

Comment on lines +103 to +105
queryFn: async ({ pageParam }) =>
await fetchCommentsPage({ after: pageParam, articleId }),
queryKey: blogQueryKeys.comments(articleId),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Scope personalized comment queries to the current viewer

When an author or moderator loads a thread, its response can contain hidden comments and moderation reasons, but this cache key depends only on the article. Signing out while the article remains mounted leaves that privileged response rendered for the anonymous session: the sign-out action only removes the identity-query prefixes listed in tanstack/auth/queries.ts, which do not include blog comments, and invalidating the router does not invalidate this component's query. Include the viewer identity in the thread query key and avoid retaining the previous viewer's data when the session changes.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ce4f0382a2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +36 to +39
article: field.relation({
target: () => blogPostContentType,
required: true,
onDelete: "cascade",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Synchronize comment search documents after localized post changes

For the newly added blog comments, the parent is a localized content type, but its editorial mutations take the syncContentLocalizedSearch branch in editorial-effects.ts. That function never calls syncContentSearchDependents; only the non-localized syncContentSearch path does. Consequently, hiding, unpublishing or deleting a blog article leaves its previously indexed comments publicly searchable in search, Discover and profile timelines, even though their thread is no longer public. Extend dependent synchronization to localized parent mutations before enabling this relationship.

Useful? React with 👍 / 👎.

Comment on lines +86 to +90
const deleted = row.deletedAt !== null && row.deletedAt !== undefined;
const owns =
update.own &&
!hidden &&
!deleted &&

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Select deletion state before authorizing public edits

When a comment with replies is deleted, its row remains as a placeholder, but lockSelection() in public-write-service.ts does not select deletedAt. Both findEditable and update pass that partial row to this authorization function, so deleted is always false and an author whose edit window remains open can still retrieve and modify a moderator-deleted comment through the public edit endpoints. Include the deletion column in the authorization selection so the new guard actually rejects edits to deleted placeholders.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8ea5a68984

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +112 to +115
if (result && reason) {
await tx
.update(table)
.set({ hiddenReason: reason })

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve moderation reasons when hiding is a no-op

When a moderator has already hidden a comment, its author can still call /hide if their role allows hiding their own content: canHideContentRecord permits that action even when someone else hid the record. The visibility service returns a non-null result with changed: false, but this condition nevertheless overwrites hiddenReason with the author's supplied text. This lets authors replace the moderator's explanation without moderation permissions. Only write the reason when the visibility transition actually changed the record, or separately authorize changes to an existing moderation reason.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: edbba6f942

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +55 to +59
args: {
query: {
root: String(articleId),
first,
...(after ? { after } : {}),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Resolve thread roots in the article's active locale

For an article published in Polish while its English translation is missing or unpublished, the article page loads successfully but this new comments request always returns 404. The thread handler in content/server/public-routes.ts calls rootService.findById(rootId, { select: [] }) without a locale, and localized-public-service.ts consequently checks only the content type's default locale (en for blog posts). Unlike the article query, this integration never supplies the reader's locale. Add locale-aware root resolution to the thread endpoint and pass the article's locale so comments remain readable on articles published only in a non-default language.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b970d6ff84

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

<div className="min-w-0 lg:col-start-2 lg:row-start-2">
<PostComments
articleAuthorIds={articleAuthorIds}
articleHref={blogPostHref(item.friendlyUrl)}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Localize the article URL passed to comment links

On a non-default-language article whose translated slug differs from the default-language slug, this passes an unprefixed internal URL to PostComments. That component uses it directly in both the date's native <a> and SharePopover, neither of which applies the router's locale rewrite. Clicking or sharing a comment on /pl/blog/article/polski-slug therefore produces /blog/article/polski-slug, which resolves in the default locale and can return 404 because that translation has a different slug. Apply localizeHref with the current locale before passing this URL so both permalinks and shared links retain the article's language.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5b26465282

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +29 to +31
module: "content/comments",
path: "/{slug}",
args: { params: { slug: encodeURIComponent(request.slug) } },

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Resolve comment permalinks for authorized hidden-article readers

When an article is hidden, its author or moderator can read its comments through the new thread endpoint, but following a comment's permalink still returns 404. This first lookup uses public-service.ts's readOne, whose parent-visibility filter rejects hidden articles even for authorized readers; the subsequent posts/{id}/slug lookup also requests only a public article. Consequently, the comment URLs used by ModCP cannot open these conversations. Add an authorized hidden-parent resolution path for both lookups, keeping those responses private as the thread endpoint does.

Useful? React with 👍 / 👎.

@aXenDeveloper
aXenDeveloper force-pushed the feat/comments_content_engine branch from 7a536e2 to 5a2f140 Compare October 27, 2026 12:57
@aXenDeveloper
aXenDeveloper added this pull request to stack #905 October 27, 2026 12:57
- Shared comments controller and UI for Content Engine threads, drawn on the card surface
- Blog notifies comment authors about replies; replies-only thread notifications
- Docs: comments guides rebuilt around the shared Comments API, replies-only and article-author notification setups, refreshed screenshots
- Tests for the shared comments module and replies-only threads

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5a2f140282

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +298 to +303
if (await hasReplies(id)) {
await c
.get("db")
.update(table)
.set({ deletedAt: new Date(), deletedBy: user.id })
.where(eq(columns.id, id as never));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Queue notification cleanup when retaining a deleted placeholder

When a comment with replies is deleted, this branch only updates its deletion columns and never calls recordContentNotificationCleanup, unlike the physical-delete service paths. Its notification receipts and unread counts therefore remain indefinitely, while contentNotificationAccess rejects the deleted row and renders its inbox item unavailable. For grouped notifications, deleting the latest contributing comment also makes the entire group unavailable even when other contributions remain public. Store the cleanup intent in the same transaction as the placeholder update so the existing cleanup worker removes or repairs these items.

Useful? React with 👍 / 👎.

return c.json({ id }, 200, { "Cache-Control": "private, no-store" });
}

await removeRow(row);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Serialize the reply check with comment deletion

If another request creates a reply after hasReplies(id) returns false but before removeRow(row) deletes the comment, the new reply's ON DELETE SET NULL parent relation is cleared and it becomes a top-level comment instead of remaining beneath a deleted placeholder. The reply-placement validation does not lock the parent, and this handler performs the existence check outside the deletion transaction, so this interleaving is permitted. Serialize the reply check and deletion with reply creation, including the ancestor-pruning path, to preserve the conversation structure.

Useful? React with 👍 / 👎.

@aXenDeveloper
aXenDeveloper force-pushed the feat/comments_content_engine branch from 5a2f140 to 3244eed Compare October 27, 2026 13:17
}) => {
const t = useTranslations("core.global.share");
const absoluteUrl = React.useMemo(
() => new URL(url, window.location.href).href,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

React Doctor · react-doctor/no-unguarded-browser-global-in-render-or-hook-init (error)

window is read while React is rendering on the server, where browser globals are unavailable. Move the read into an effect or event, or provide a stable server snapshot.

Fix → Move browser-only reads into an effect or event, guard them behind a client-only render path, or use useSyncExternalStore with a stable server snapshot.

Docs

* state, the **Reply** button, the actions menu, and the edit and reply forms
* in place. A placeholder stands in for a removed comment.
*/
export const ContentCommentItem = <TRecord,>({

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

React Doctor · react-doctor/no-high-complexity-react-function (warning)

ContentCommentItem has cyclomatic complexity 23, cognitive complexity 23, and maximum nesting depth 2, so its React logic is hard to understand and change. Extract independent branches into components or hooks.

Fix → Extract independent render branches and state logic into focused components or hooks until the control flow is easy to follow.

Docs

<EmptyMedia variant="icon">
<MessageSquareIcon aria-hidden="true" />
</EmptyMedia>
<EmptyTitle render={<h3 />}>{t("empty.title")}</EmptyTitle>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

React Doctor · react-doctor/heading-has-content (warning)

Blind users can't use this heading to navigate because screen readers skip it empty, so add text, aria-label, or aria-labelledby.

Fix → Put readable text in every heading.

Docs

*
* `children` adds your own menu items above the shared ones.
*/
export const ContentCommentActions = ({

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

React Doctor · react-doctor/no-high-complexity-react-function (warning)

ContentCommentActions has cyclomatic complexity 23, cognitive complexity 23, and maximum nesting depth 2, so its React logic is hard to understand and change. Extract independent branches into components or hooks.

Fix → Extract independent render branches and state logic into focused components or hooks until the control flow is easy to follow.

Docs

repliesInclude(child, anchorId),
);

const CommentEntry = ({

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

React Doctor · react-doctor/no-high-complexity-react-function (warning)

CommentEntry has cyclomatic complexity 23, cognitive complexity 31, and maximum nesting depth 2, so its React logic is hard to understand and change. Extract independent branches into components or hooks.

Fix → Extract independent render branches and state logic into focused components or hooks until the control flow is easy to follow.

Docs

<EmptyMedia variant="icon">
<MessageSquareIcon aria-hidden="true" />
</EmptyMedia>
<EmptyTitle render={<h3 />}>{t("empty.title")}</EmptyTitle>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

React Doctor · react-doctor/heading-has-content (warning)

Blind users can't use this heading to navigate because screen readers skip it empty, so add text, aria-label, or aria-labelledby.

Fix → Put readable text in every heading.

Docs

@aXenDeveloper
aXenDeveloper merged commit 797e9eb into canary Oct 27, 2026
7 checks passed
@aXenDeveloper
aXenDeveloper deleted the feat/comments_content_engine branch October 27, 2026 14:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

💡 Feature A new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant